////////////////////////////////////////////////////////////////////////////////

#ifndef _SERVERENGINE_H_
#include "serverengine.h"
#endif

////////////////////////////////////////////////////////////////////////////////

#ifndef _SERVER_H_
#include "server.h"
#endif

#ifndef _TIMER_H_
#include "timer.h"
#endif

#ifndef _CLIENTINPUTPACKET_H_
#include "clientinputpacket.h"
#endif

#ifndef _CLIENTINFOPACKET_H_
#include "clientinfopacket.h"
#endif

#ifndef _SCOPEGUARD_H_
#include "scopeguard.h"
#endif

#ifndef _SERVERMAPPARSER_H_
#include "servermapparser.h"
#endif

#ifndef _SERVERSTATEPACKET_H_
#include "serverstatepacket.h"
#endif

#ifndef _SERVERINFOPACKET_H_
#include "serverinfopacket.h"
#endif

#ifndef _SERVERSTARTPACKET_H_
#include "serverstartpacket.h"
#endif

#include <cassert>
#include <iostream>
#include <string>

////////////////////////////////////////////////////////////////////////////////


ServerEngine::ServerEngine() 
: m_Battlefield(this)
{
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::UpdateState()
{
    size_t dt = GetTimeDiffFromPrevUpdate();

    if (dt > 0)
    {
        ScopeGuard guard(m_Battlefield);
        m_Battlefield.Update(dt);
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::UpdateClientInput( int _clientID, const ClientInputPacket& _clientInputPacket )
{
    ScopeGuard guard(m_Battlefield);

    m_Battlefield.SetClientInput( _clientID,
                                  _clientInputPacket.GetClientInput(),
                                  _clientInputPacket.GetCreationTime() );
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::UpdateClientInfo( int _clientID, const ClientInfoPacket& _clientInfoPacket )
{
    ScopeGuard guard(m_Battlefield);

    if ( !m_Battlefield.HasPlayer(_clientID) )
    {
        m_ClientsID.insert(_clientID);
        m_Battlefield.AddPlayer(_clientID);

        // Send packet with start info
        ServerStartPacket startPacket( m_MapName.c_str() );
        Server::Instance().Network().SendServerInfo(_clientID, startPacket);
    }

    m_ClientsStat[_clientID].m_NickName = _clientInfoPacket.GetClientInfo().GetNickName();
}


////////////////////////////////////////////////////////////////////////////////


ServerState ServerEngine::GetState() const
{
    ScopeGuard guard(m_Battlefield);
    return m_Battlefield.GetState();
}

 
////////////////////////////////////////////////////////////////////////////////


size_t ServerEngine::GetTimeDiffFromPrevUpdate() const
{
    // Previous time
    static size_t prevTime = Timer::GetCurrTime();

    // Current time
    size_t currTime = Timer::GetCurrTime();

    // Get difference
    size_t dt = currTime - prevTime;

    // Save previous time
    prevTime = currTime;

    // Return difference
    return dt;
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::RemoveClient( int _clientID )
{
    ScopeGuard guard(m_Battlefield);

    m_ClientsID.erase(_clientID);
    m_ClientsStat.erase(_clientID);
    m_Battlefield.RemovePlayer(_clientID);
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::LoadMap()
{
    std::cout << "Enter game map name: ";
    std::cin >> m_MapName;
    ServerMapParser parser( m_MapName.c_str() );
    parser.Parse();
    m_Battlefield.SetMap( parser.GetMap() );
}


////////////////////////////////////////////////////////////////////////////////


ServerBattlefield& ServerEngine::Battlefield()
{
    return m_Battlefield;
}


////////////////////////////////////////////////////////////////////////////////


const IntSet& ServerEngine::GetClientsIDs() const
{
    return m_ClientsID;
}


////////////////////////////////////////////////////////////////////////////////


void ServerEngine::HandleKilling( int _playerID, int _killerID )
{
    m_ClientsStat[_playerID].m_Dies++;
    m_ClientsStat[_killerID].m_Kills++;
    Server::Instance().NotifyAboutKilling(_playerID, _killerID);
}


////////////////////////////////////////////////////////////////////////////////
